<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2024/4/23
 * Time: 14:23
 */

namespace app\logic\index\plan;


use app\common\lib\Common;
use app\common\lib\DetectFaceAdvance;
use app\common\lib\Guzzle;
use app\common\lib\RedisQueue;
use app\exception\IndexException;
use app\logic\BaseLogic;
use app\model\consume\ConsumePointLogModel;
use app\model\image\ImageCommandPlanModel;
use app\model\novel\NovelChapterPartModel;
use app\model\plan\NovelChapterPartOverseaModel;
use app\model\plan\PromotionPlanOverseaModel;
use app\model\plan\PromotionPlanPartImageModel;
use app\model\queue\AiImageRequestQueueModel;
use app\model\redis\RedisQueueModel;
use app\model\tencent\TimbreModel;
use app\model\user\UserNovelChapterPartModel;
use app\model\user\UserPointFlowModel;
use app\model\user\UserPromotionArticleModel;
use app\model\user\UserPromotionOverseaModel;
use app\model\user\UserPromotionPlanModel;
use app\model\user\UserPromotionVideoModel;
use support\Cache;
use support\Db;

class PlanLogic extends BaseLogic
{
    protected $model;

    protected static $instance;

    public function __construct()
    {
        parent::__construct();
        $this->model = \app\model\plan\PromotionPlanModel::getInstance();
    }

    public static function getInstance()
    {
//        if (is_object(self::$instance)) {
//            return self::$instance;
//        }

        return  new self();
    }

    /**
     * 扣除点数-立即生成逻辑
     * @param $param
     */
    public function generateAndConsume($param)
    {
        if(Common::setnx('generateAndConsume_'.request()->curUserId)==false){
            throw new IndexException(4020,'请求频繁');
        }

        if(!empty($param['novel_sn']) || !empty($param['planid'])){
           return $this->generateAndConsumeByNovel($param);
        }else if(!empty($param['overseaid'])){
            return $this->generateAndConsumeByOversea($param);
        }else if(!empty($param['articleid'])){
           return $this->generateAndConsumeByArticle($param);
        }else if(!empty($param['videoid'])){
           return $this->generateAndConsumeByVideo($param);
        }
    }

    protected function generateAndConsumeByNovel($param)
    {
        if(!empty($param['planid'])){
            $plan = $this->model->getWhere(['isdel' => 0, 'status' => 1, 'id' => $param['planid']])->first();
        }else{
            //随机获取当前小说的一个方案
            $plan = $this->model->getWhere(['isdel' => 0, 'status' => 1, 'novel_sn' => $param['novel_sn']])->orderBy(Db::Raw('RAND()'))->first();
        }
        if ($plan == false) {
            throw new IndexException(4020, '当前推文不可用');
        }

        //获取该方案的段落
        $batch = NovelChapterPartModel::getInstance()->getWhere(['planid' => $plan['id'], 'isdel' => 0])->orderBy('batch', 'desc')->value('batch');
        $parts = NovelChapterPartModel::getInstance()->getWhere(['planid' => $plan['id'], 'isdel' => 0, 'batch' => $batch])->orderBy('number', 'asc')->get();
        if (empty($parts)) {
            throw new IndexException(4020, '当前推文不可用');
        }

        //todo 1 首先扣除用户点数
        $consumePoint = round(count($parts->toArray()) * config('param.image_consume_point',10));
        $pointData = $this->consumePoint(['consume_point'=>$consumePoint]);

        try {
            Db::connection('mysql')->beginTransaction();
            //todo 1 插入用户推文方案
            $userPlanInsert = [
                'user_sn'=>request()->curUserId,
                'name'=>$plan['name'],
                'planid'=>$plan['id'],
                'chapterid'=>$plan['chapterid'],
                'novel_sn'=>$plan['novel_sn'],
                'part_nums'=>$plan['part_nums']??0,
                'musicid'=>$plan['musicid']??0,
                'timbreid'=>$plan['timbreid']??0,
                'music_volume'=>$plan['music_volume']??10,
                'timbre_volume'=>$plan['timbre_volume']??10,
                'speak_speed'=>$plan['speak_speed']??10,
                'fontid'=>$plan['fontid']??0,
                'modelid'=>$plan['modelid']??0,
                'templateid'=>$plan['ai_image_command_id']??0,
                'plan_type'=>1,
                'video_rate'=>$plan['video_rate']??'3:2',
                'articleid'=>0,
                'videoid'=>0,
                'ai_images_nums'=>$plan['ai_images_nums']??1,
                'ai_image_command'=>$plan['ai_image_command']??'',
                'spread_type'=>$plan['spread_type']??'1',
            ];
            $userPlanid = UserPromotionPlanModel::getInstance()->insertGetId($userPlanInsert);

            //todo 2 插入用户推文方案片段
            $userPartInserts = [];
            foreach ($parts as $part) {
                $userPartInsert = [
                    'user_sn'=>request()->curUserId,
                    'user_planid'=>$userPlanid,
                    'planid'=>$part['planid'],
                    'chapterid'=>$part['chapterid'],
                    'novel_sn'=>$part['novel_sn'],
                    'partid'=>$part['id']??0,
                    'content'=>$part['content']??0,
                    'number'=>$part['number']??0,
                    'subtitle'=>$part['subtitle']??'',
                    'prompt'=>$part['prompt']??'',
                    'analyze_content'=>$part['analyze_content']??0,
                    'articleid'=>0,
                    'videoid'=>0,
                    'analyze_content_ai_command'=>$part['analyze_content_ai_command']??'',
                    'prompt_ai_command'=>$part['prompt_ai_command']??'',
                    'roleids'=>$part['roleids']??'',
                    'ai_image_command_seed'=>$part['ai_image_command_seed']??'-1',
                    'refer_image'=>$part['refer_image']??'',
                    'more_people_prompt'=>$part['more_people_prompt']??'',
                ];

                $userPartInserts[] = $userPartInsert;
            }
            UserNovelChapterPartModel::getInstance()->insert($userPartInserts);

            //todo 3 插入用户消费记录
            $insertLog = [
                'user_sn'      => request()->curUserId,
                'point'        => $pointData['consume_point'],
                'novel_sn'     => $plan['novel_sn'],
                'chapterid'    => $plan['chapterid'],
                'planid'       => $plan['id'],
                'source_table' => UserPromotionPlanModel::getInstance()->getTable(),
                'sourceid'     => $userPlanid,
                'plan_type'     => 1,
            ];
            $logId     = ConsumePointLogModel::getInstance()->insertGetId($insertLog);

            //todo 4 插入用户消费流水
            if ($pointData['consume_vip_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_vip_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => $pointData['is_vip']==2 ? 3 : 1,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }

            if ($pointData['consume_buy_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_buy_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => 2,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }
            Db::connection('mysql')->commit();
        }catch (IndexException $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Exception $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        $userPlan = UserPromotionPlanModel::getInstance()->find($userPlanid);
        $this->unsetCommonFields($userPlan, ['created_at', 'updated_at']);

        $userPlan['parts'] = UserNovelChapterPartModel::getInstance()->getWhere(['user_planid' => $userPlanid])->orderBy('number', 'asc')->get();
        $this->unsetCommonFields($userPlan['parts'], ['created_at', 'updated_at', 'timbre_voice_info', 'subtitle']);

        //$userPlan['timbreid'] = TimbreModel::getInstance()->getWhere(['id'=>$userPlan['timbreid']])->value('timbreid');

        //生成唯一的请求id
        $requestId = Common::getRequestId();

        // 队列名
        $queue = 'asyncPlanPartAiImage';
        // 数据，可以直接传数组，无需序列化
        $data = ['requestid' => $requestId, 'user_planid' => $userPlanid];
        // 投递消息
        RedisQueue::getInstance()->sendQueue($queue, $data);

        $userPlan['requestid'] = $requestId;
        return $userPlan;
    }


    /**
     * 海外推广-扣除点数生成
     * @param $param
     * @return UserPromotionPlanModel|UserPromotionPlanModel[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|null
     * @throws IndexException
     * @throws \Throwable
     */
    protected function generateAndConsumeByOversea($param)
    {
        $plan = UserPromotionOverseaModel::getInstance()->getWhere(['id' => $param['overseaid']])->first();
        if ($plan == false) {
            throw new IndexException(4020, '当前推文不可用');
        }

        //获取该方案的段落
        $parts = json_decode($plan['part_content'], true);
        $subTitles = json_decode($plan['subtitle'], true);

        if (empty($parts)) {
            throw new IndexException(4020, '当前推文不可用');
        }

        //处理素材
        $localVideo = $plan['local_video'] ? json_decode($plan['local_video'], true):[];
        $materialData = $plan['material_data'] ? json_decode($plan['material_data'], true):[];
        if(empty($localVideo)  && empty($materialData['heigh']) &&  empty($materialData['normal'])){
            throw new IndexException(4020, '视频素材不能为空');
        }

        //todo 1 首先扣除用户点数
        $strLen = 0;
        foreach ($parts as $part){
            $strLen += strlen($part);
        }
        $consumePoint = round(ceil($strLen/3000)*10);
        $pointData = $this->consumePoint(['consume_point'=>$consumePoint]);

        try {
            Db::connection('mysql')->beginTransaction();
            //todo 1 插入用户推文方案
            $userPlanInsert = [
                'user_sn'       => request()->curUserId,
                'novel_sn'      => $plan['novel_sn'] ?? '0',
                'chapterid'     => $plan['chapterid'] ?? '0',
                'planid'        => $plan['planid'],
                'part_nums'     => count($parts) ?? 0,
                'musicid'       => $plan['musicid'] ?? 0,
                'timbreid'      => $plan['timbreid'] ?? 0,
                'music_volume'  => $plan['music_volume'] ?? 10,
                'timbre_volume' => $plan['timbre_volume'] ?? 10,
                'speak_speed'   => $plan['speak_speed'] ?? 10,
                'fontid'        => $plan['fontid'] ?? 0,
                'plan_type'     => 4,
                'spread_type'   => !empty($plan['novel_sn']) ? 3 : '0',
                'video_rate'    => $plan['video_rate'] ?? '9:16',
                'overseaid'     => $plan['id'] ?? '0',

                'material_id'    => $plan['material_id'] ?? '',
                'settings'       => $plan['settings'] ?? '',
                'font_size'      => $plan['font_size'] ?? '0',
                'caption_post_x' => $plan['caption_post_x'] ?? '0',
                'caption_post_y' => $plan['caption_post_y'] ?? '0',
                'lang'           => $plan['lang'] ?? 'en',
                'material_data'  => json_encode($materialData, 256),
                'material_video' => $localVideo ? json_encode($localVideo, 256) : '',

                /*2024-09-18迭代新增*/
                'style_type' => $plan['style_type'] ?? 1,
                'chat_images'=>$plan['chat_images'] ?? '' ,/*聊天框的图片数组*/
                'chat_messages'=>$plan['chat_messages'] ?? '' ,/*内容图片数组*/
                'card_image'=>$plan['card_image'] ?? '' ,/*卡片图片地址*/
                'card_remain'=>$plan['card_remain']?? 0 ,/*卡片停留时长(秒)*/
                'card_top'=>$plan['card_top']?? 0 ,/*卡片顶部距离百分比*/
                'card_content' => $plan['card_content'] ?? '',/*卡片聊天文本*/
            ];
            $userPlanid = UserPromotionPlanModel::getInstance()->insertGetId($userPlanInsert);

            //todo 2 插入用户推文方案片段
            $userPartInserts = [];
            foreach ($parts as $k=>$part) {
                $userPartInsert = [
                    'user_sn'     => request()->curUserId,
                    'user_planid' => $userPlanid,
                    'planid'      => $plan['planid'] ?? 0,
                    'chapterid'   => $plan['chapterid'] ?? '0',
                    'novel_sn'    => $plan['novel_sn'] ?? '0',
                    'overseaid'   => $plan['id'],
                    'content'     => $part,
                    'number'      => $k + 1,
                    'subtitle'    => json_encode($subTitles[$k] ?? [], 256),
                ];
                $userPartInserts[] = $userPartInsert;
            }
            UserNovelChapterPartModel::getInstance()->insert($userPartInserts);

            //todo 3 插入用户消费记录
            $insertLog = [
                'user_sn'      => request()->curUserId,
                'chapterid'    => $plan['chapterid'] ?? '0',
                'novel_sn'     => $plan['novel_sn'] ?? '0',
                'planid'       => $plan['planid']??0,
                'point'        => $pointData['consume_point'],
                'overseaid'       => $plan['id'],
                'source_table' => UserPromotionPlanModel::getInstance()->getTable(),
                'sourceid'     => $userPlanid,
                'plan_type'     => 5,
            ];
            $logId     = ConsumePointLogModel::getInstance()->insertGetId($insertLog);

            //todo 4 插入用户消费流水
            if ($pointData['consume_vip_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_vip_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => $pointData['is_vip']==2 ? 3 : 1,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }

            if ($pointData['consume_buy_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_buy_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => 2,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }
            Db::connection('mysql')->commit();
        }catch (IndexException $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Exception $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        $userPlan = UserPromotionPlanModel::getInstance()->find($userPlanid);
        $this->unsetCommonFields($userPlan, ['created_at', 'updated_at','material_data','settings']);

        $userPlan['parts'] = UserNovelChapterPartModel::getInstance()->getWhere(['user_planid' => $userPlanid])->orderBy('number', 'asc')->get();
        $this->unsetCommonFields($userPlan['parts'], ['created_at', 'updated_at', 'timbre_voice_info', 'subtitle']);

        //$userPlan['timbreid'] = TimbreModel::getInstance()->getWhere(['id'=>$userPlan['timbreid']])->value('timbreid');

        if($userPlan->status == 0){

            //生成唯一的请求id
            $requestId = Common::getRequestId();

            // 队列名
            $queue = 'generatedOverseaVideo';
            // 数据，可以直接传数组，无需序列化
            $data = ['requestid' => $requestId, 'user_planid' => $userPlanid];
            // 投递消息
            RedisQueue::getInstance()->sendQueue($queue, $data);

            $userPlan['requestid'] = $requestId;
        }

        return $userPlan;
    }

    protected function generateAndConsumeByArticle($param)
    {
        $plan = UserPromotionArticleModel::getInstance()->getWhere(['id' => $param['articleid']])->first();
        if ($plan == false) {
            throw new IndexException(4020, '当前推文不可用');
        }
        $imageCommand = ImageCommandPlanModel::getInstance()->find($plan['templateid']);

        if(!empty($param['parts'])){
            $parts = json_decode($param['parts'], true);
            //分段分析和字幕
            list($parts,$subTitles) = partsAnalyze($parts);
        }else{
            //获取该方案的段落
            $parts = json_decode($plan['part_content'], true);
            $subTitles = json_decode($plan['subtitle'], true);
        }

        if (empty($parts)) {
            throw new IndexException(4020, '当前推文不可用');
        }
        $parts = array_values(array_filter($parts));

        //todo 1 首先扣除用户点数
        $consumePoint = round(count($parts) * config('param.image_consume_point',10));
        $pointData = $this->consumePoint(['consume_point'=>$consumePoint]);

        try {
            Db::connection('mysql')->beginTransaction();
            //todo 1 插入用户推文方案
            $userPlanInsert = [
                'user_sn'=>request()->curUserId,
                'part_nums'=>count($parts),
                'musicid'=>$plan['musicid']??0,
                'timbreid'=>$plan['timbreid']??0,
                'music_volume'=>$plan['music_volume']??5,
                'timbre_volume'=>$plan['timbre_volume']??10,
                'speak_speed'=>$plan['speak_speed']??10,
                'fontid'=>$plan['fontid']??0,
                'modelid'=>$plan['modelid']??0,
                'templateid'=>$plan['templateid']??0,
                'plan_type'=>2,
                'video_rate'=>$plan['video_rate']??'3:2',
                'articleid'=>$plan['id'],
                'videoid'=>0,
                'ai_images_nums'=>1,
                'ai_image_command'=>$imageCommand['ai_image_command']??'',
            ];

            $userPlanid = UserPromotionPlanModel::getInstance()->insertGetId($userPlanInsert);

            (new UserPromotionArticleModel())->getWhere(['id' => $plan['id']])->update(['user_planid'=>$userPlanid]);

            //todo 2 插入用户推文方案片段
            $userPartInserts = [];
            foreach ($parts as $k=>$part) {
                $userPartInsert = [
                    'user_sn'=>request()->curUserId,
                    'user_planid'=>$userPlanid,
                    'articleid'=>$plan['id'],
                    'content'=>$part,
                    'number'=>$k+1,
                    'subtitle'=>json_encode($subTitles[$k]??[],256),
                ];
                $userPartInserts[] = $userPartInsert;
            }
            UserNovelChapterPartModel::getInstance()->insert($userPartInserts);

            //todo 3 插入用户消费记录
            $insertLog = [
                'user_sn'      => request()->curUserId,
                'point'        => $pointData['consume_point'],
                'articleid'       => $plan['id'],
                'source_table' => UserPromotionPlanModel::getInstance()->getTable(),
                'sourceid'     => $userPlanid,
                'plan_type'     => 2,
            ];
            $logId     = ConsumePointLogModel::getInstance()->insertGetId($insertLog);

            //todo 4 插入用户消费流水
            if ($pointData['consume_vip_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_vip_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => $pointData['is_vip']==2 ? 3 : 1,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }

            if ($pointData['consume_buy_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_buy_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => 2,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }
            Db::connection('mysql')->commit();
        }catch (IndexException $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Exception $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        $userPlan = UserPromotionPlanModel::getInstance()->find($userPlanid);
        $this->unsetCommonFields($userPlan, ['created_at', 'updated_at']);

        $userPlan['parts'] = UserNovelChapterPartModel::getInstance()->getWhere(['user_planid' => $userPlanid])->orderBy('number', 'asc')->get();
        $this->unsetCommonFields($userPlan['parts'], ['created_at', 'updated_at', 'timbre_voice_info', 'subtitle']);

        //生成唯一的请求id
        $requestId = Common::getRequestId();

        // 队列名
        $queue = 'asyncPlanPartAiImage';
        // 数据，可以直接传数组，无需序列化
        $data = ['requestid' => $requestId, 'user_planid' => $userPlanid];
        // 投递消息
        RedisQueue::getInstance()->sendQueue($queue, $data);

        $userPlan['requestid'] = $requestId;
        return $userPlan;
    }

    protected function generateAndConsumeByVideo($param)
    {
        $plan = UserPromotionVideoModel::getInstance()->getWhere(['id' => $param['videoid']])->first();
        if ($plan == false) {
            throw new IndexException(4020, '当前推文不可用');
        }
        $imageCommand = ImageCommandPlanModel::getInstance()->find($plan['templateid']);

        if(!empty($param['parts'])){
            $parts = json_decode($param['parts'], true);
            //分段分析和字幕
            list($parts,$subTitles) = partsAnalyze($parts);
        }else{
            //获取该方案的段落
            $parts = json_decode($plan['part_content'], true);
            $subTitles = json_decode($plan['subtitle'], true);
        }
        if (empty($parts)) {
            throw new IndexException(4020, '当前推文不可用');
        }
        $parts = array_values(array_filter($parts));

        //todo 1 首先扣除用户点数
        $consumePoint = round(count($parts) * config('param.image_consume_point',10));
        $pointData = $this->consumePoint(['consume_point'=>$consumePoint]);

        try {
            Db::connection('mysql')->beginTransaction();
            //todo 1 插入用户推文方案
            $userPlanInsert = [
                'user_sn'=>request()->curUserId,
                'part_nums'=>count($parts),
                'musicid'=>$plan['musicid']??0,
                'timbreid'=>$plan['timbreid']??0,
                'music_volume'=>$plan['music_volume']??5,
                'timbre_volume'=>$plan['timbre_volume']??10,
                'speak_speed'=>$plan['speak_speed']??10,
                'fontid'=>$plan['fontid']??0,
                'modelid'=>$plan['modelid']??0,
                'templateid'=>$plan['templateid']??0,
                'plan_type'=>3,
                'video_rate'=>$plan['video_rate']??'3:2',
                'articleid'=>0,
                'videoid'=>$plan['id'],
                'ai_images_nums'=>1,
                'ai_image_command'=>$imageCommand['ai_image_command']??'',
            ];

            $userPlanid = UserPromotionPlanModel::getInstance()->insertGetId($userPlanInsert);

            (new UserPromotionVideoModel())->getWhere(['id' => $plan['id']])->update(['user_planid'=>$userPlanid]);

            //todo 2 插入用户推文方案片段
            $userPartInserts = [];
            foreach ($parts as $k=>$part) {
                $userPartInsert = [
                    'user_sn'=>request()->curUserId,
                    'user_planid'=>$userPlanid,
                    'videoid'=>$plan['id'],
                    'content'=>$part,
                    'number'=>$k+1,
                    'subtitle'=>json_encode($subTitles[$k]??[],256),
                ];
                $userPartInserts[] = $userPartInsert;
            }
            UserNovelChapterPartModel::getInstance()->insert($userPartInserts);

            //todo 3 插入用户消费记录
            $insertLog = [
                'user_sn'      => request()->curUserId,
                'point'        => $pointData['consume_point'],
                'videoid'       => $plan['id'],
                'source_table' => UserPromotionPlanModel::getInstance()->getTable(),
                'sourceid'     => $userPlanid,
                'plan_type'     => 3,
            ];
            $logId     = ConsumePointLogModel::getInstance()->insertGetId($insertLog);

            //todo 4 插入用户消费流水
            if ($pointData['consume_vip_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_vip_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => $pointData['is_vip']==2 ? 3 : 1,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }

            if ($pointData['consume_buy_point'] > 0) {
                $insert = [
                    'user_sn'      => request()->curUserId,
                    'nums'         => -$pointData['consume_buy_point'],
                    'sourceid'     => $logId,
                    'source_table' => ConsumePointLogModel::getInstance()->getTable(),
                    'type'         => 2,
                    'way'          => 2,
                ];
                UserPointFlowModel::getInstance()->insert($insert);
            }
            Db::connection('mysql')->commit();
        }catch (IndexException $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Exception $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        $userPlan = UserPromotionPlanModel::getInstance()->find($userPlanid);
        $this->unsetCommonFields($userPlan, ['created_at', 'updated_at']);

        $userPlan['parts'] = UserNovelChapterPartModel::getInstance()->getWhere(['user_planid' => $userPlanid])->orderBy('number', 'asc')->get();
        $this->unsetCommonFields($userPlan['parts'], ['created_at', 'updated_at', 'timbre_voice_info', 'subtitle']);

        //生成唯一的请求id
        $requestId = Common::getRequestId();

        // 队列名
        $queue = 'asyncPlanPartAiImage';
        // 数据，可以直接传数组，无需序列化
        $data = ['requestid' => $requestId, 'user_planid' => $userPlanid];
        // 投递消息
        RedisQueue::getInstance()->sendQueue($queue, $data);

        $userPlan['requestid'] = $requestId;
        return $userPlan;
    }

    public function getUserPartAiImage($param)
    {
        $field = ['status','requestid','source'];
        $imagQueues = AiImageRequestQueueModel::getInstance()->getWhere(['source_requestid'=>$param['requestid']])->get($field)->toArray();
        $first = [];
        foreach ($imagQueues as $val){
            $sourceArr = explode('_',$val['source']);
            $userPartId = array_pop($sourceArr);
            if($param['user_partid']==$userPartId){
                $first = $val;
            }
        }

        if(empty($first)){
            $cacheKey = 'async_plan_part_ai_image_' . $param['requestid'];
            $cache = Cache::get($cacheKey);
            if (!empty($cache) && $cache['progress'] == -1) {
                return [
                    'progress' => -1,
                    'image' => '',
                    'ai_images_arr' => [],
                    'ai_image_face_arr' => [],
                    'analyze_content' => '',
                    'content' => '',
                    'prompt' => '',
                    'message' => '生成失败',
                ];
            }

/*
            //走到这里，可以走的是预备图
            $userPart = UserNovelChapterPartModel::getInstance()->find($param['user_partid']);

            $where = ['user_sn'=>request()->curUserId, 'userpartid'=>$userPart['id'], 'status'=>2];
            $imageData = PromotionPlanPartImageModel::getInstance()->getWhere($where)->get()->toArray();
            \support\Log::info("getUserPartAiImage imageData ", [$imageData]);
            if(!empty($imageData)){
                $aiImagFaceArrs = [];
                $images = [];
                foreach ($imageData as $image){
                    $images[] = $image['ai_image'];
                    $aiImagFaceArr = $image['ai_image_face_arr'] ? json_decode($image['ai_image_face_arr'],true)[0] :[];
                    $aiImagFaceArr && $aiImagFaceArrs = array_merge($aiImagFaceArrs,$aiImagFaceArr);
                }
                return [
                    'progress'=>$images[0]?100:0,
                    'image'=>$images[0]??'',
                    'ai_images_arr'=>$images,
                    'ai_image_face_arr_bak'=>$aiImagFaceArrs,
                    'analyze_content'=>$userPart['analyze_content']?:'',
                    'content'=>$userPart['content']?:'',
                    'prompt'=>$userPart['prompt']?:'',
                    'message'=>!empty($images[0])?'生成成功':'排队中...',
                ];
            }else{
                return  [
                    'progress'=>0,
                    'image'=>'',
                    'ai_images_arr'=>[],
                    'ai_image_face_arr'=>[],
                    'analyze_content'=>'',
                    'content'=>'',
                    'prompt'=>'',
                    'message'=>'等待加入队列',
                ];
            }

    */
        }

        $data = [
            'progress'=>0,
            'image'=>'',
            'ai_images_arr'=>[],
            'ai_image_face_arr'=>[],
            'analyze_content'=>'',
            'content'=>'',
            'prompt'=>'',
            'message'=>'生成中',
        ];


        if(isset($first['status']) && $first['status']==0){
            $n = 0;
            $queueKey = '{redis-queue}-waitingrequestAiImage';
            $redisQueues = \Webman\RedisQueue\Redis::connection('ai_image_consumer')->lRange($queueKey,0,-1);
            if($redisQueues){
                $redisQueues = array_reverse($redisQueues);
                foreach ($redisQueues as $k=>$q){
                    $qData = json_decode($q, true);
                    if($qData['data']['requestid']==$first['requestid']){
                        $n=($k+1);
                        break;
                    }
                }
            }

            $n>0 && $data['message'] = '排队中,'.$n.'/'.count($redisQueues);
        }elseif(isset($first['status']) && $first['status']==2){
            try{
                $aiImages = Common::getAiImageResult($first['requestid']);
                \support\Log::info("getUserPartAiImage aiImages ", [$aiImages]);
                if(!empty($aiImages)){
                    $data['progress'] = 100;
                    $data['image'] = $aiImages[0];
                    $data['ai_images_arr'] = $aiImages;

                    $userPart = UserNovelChapterPartModel::getInstance()->find($param['user_partid']);
                    if($userPart && $userPart['ai_images_bak']==$aiImages[0]){
                        $data['ai_image_face_arr'] = !empty($userPart['ai_image_face_arr_bak'])?json_decode($userPart['ai_image_face_arr_bak'], true):[];
                    }else{
                        //如果数据不是最新的，休眠3秒再获取一次
//                        $userPart = UserNovelChapterPartModel::getInstance()->find($param['user_partid']);
//                        if($userPart && $userPart['ai_images_bak']==$aiImages[0]){
//                            $data['ai_image_face_arr'] = !empty($userPart['ai_image_face_arr_bak'])?json_decode($userPart['ai_image_face_arr_bak'], true):[];
//                        }else{
//                            //获取人脸识别数据
//                            $aiImageFaceArrs = [];
//                            foreach($aiImages as $image){
//                                $aiImageFaceArr = [];
//                                $aiImageFaceArr['link'] = $image;
//                                $aiImageFaceArr['faceRectangles'] = [];
//                                try{
//                                    $res = DetectFaceAdvance::getInstance()->getFaceBody($image);
//                                    if(!empty($res['Data']['FaceRectangles'])){
//                                        $aiImageFaceArr['faceRectangles'] = $res['Data']['FaceRectangles'];
//                                    }
//                                }catch (\Throwable $e){}
//
//                                $aiImageFaceArrs[] = $aiImageFaceArr;
//
//                                //这里加上休眠是因为QPS 5/s
//                                usleep(200000);
//                            }
//                            $data['ai_image_face_arr'] = $aiImageFaceArrs;
//                        }
                    }

                    if(empty($data['ai_image_face_arr'])){
                        $data['ai_image_face_arr'] = [];
                        foreach ($data['ai_images_arr'] as $img){
                            $data['ai_image_face_arr'][] = ['link'=>$img,'faceRectangles'=>[]];
                        }
                    }
                    $data['message'] = '生成完成';
                }
            }catch (IndexException $e){
                $data['progress'] = -1;
                $data['message'] = $e->getMessage();
            }
        }elseif(isset($first['status']) && ($first['status']==3||$first['status']==4)){
            $data['progress'] = -1;
            $data['message'] = '生成失败,请稍后重试';
        }
        $userPart = UserNovelChapterPartModel::getInstance()->find($param['user_partid']);
        $data['analyze_content'] =$userPart['analyze_content']?:'';
        $data['content'] =$userPart['content']?:'';
        $data['prompt'] =$userPart['prompt']?:'';

        return $data;
    }

    public function updateUserPlan($param)
    {
        $res = Common::setnx('updateUserPlan_'.request()->curUserId);
        if($res==false){
            throw new IndexException(4020,'请求频繁');
        }

        $userPart = UserNovelChapterPartModel::getInstance()->find($param['user_partid']);
        if(empty($userPart)){
            throw new IndexException(4020,'用户方案片段不存在');
        }
//        if(!empty($param['analyze_content'])){
//            $userPart->analyze_content = $param['analyze_content'];
//            //todo 1 获取描述词
//            $content = file_get_contents(runtime_path('promto'));
//            $content .= $param['analyze_content'];
//            $param = [
//                'model'=>'gpt-3.5-turbo-1106',
//                'messages'=>[
//                    [
//                        'role'=>'system',
//                        'content'=>$content,
//                    ],
//                ],
//            ];
//            $header = [
//                'Authorization'=>config('param.zizengzeng_token'),,
//                'Content-Type'=>'application/json',
//            ];
//            $result = Guzzle::post('https://flag.smarttrot.com/','v1/chat/completions',$param,$header,'json');
//
//            $contents = explode("\n",$result['choices'][0]['message']['content']);
//            if(strpos(strtolower($contents[0]),'prompt')!==false) {
//                $prompt      = trim($contents[1], "\r");
//                $userPart->prompt = $prompt;
//            }
//        }

        if(!empty($param['prompt'])){
            $userPart->prompt = $param['prompt'];
        }
        if(!empty($param['ai_image'])){
            $aiImages = explode(',',$param['ai_image']);
            $userPart->ai_images = $userPart->ai_images_bak;
            $userPart->ai_images_arr = $userPart->ai_images_arr_bak;
            $userPart->ai_image_face_arr = $userPart->ai_image_face_arr_bak;

            UserPromotionPlanModel::getInstance()->getWhere(['id'=>$userPart->user_planid])->update(['image'=>$userPart->ai_images_bak]);
        }
//        if(!empty($param['fontid'])){
//            $userPart->fontid = $param['fontid'];
//        }
//        if(!empty($param['video_rate'])){
//            $userPart->video_rate = $param['video_rate'];
//        }
        $userPart->save();

        $data = [
            'analyze_content'=>$userPart->analyze_content,
            'prompt'=>$userPart->prompt,
        ];
        return $data;
    }

    public function generatedAiImage($param)
    {
        $res = Common::setnx('generatedAiImage_'.request()->curUserId.'_'.$param['user_partid']);
        if($res==false){
            throw new IndexException(4020,'请求频繁');
        }

        $userPart = UserNovelChapterPartModel::getInstance()->find($param['user_partid']);
        if(empty($userPart)){
            throw new IndexException(4020,'用户方案片段不存在');
        }

        //生成唯一的请求id
        $requestId = Common::getRequestId();

        // 队列名
        $queue = 'asyncPlanPartAiImage';
        // 数据，可以直接传数组，无需序列化
        $data = [
            'requestid' => $requestId,
            'user_partid' => $param['user_partid'],
            'issave' => $param['issave'] ?? 1,
            'is_fix' => !empty($param['is_fix'] )? intval($param['is_fix']): 0
        ];
        // 投递消息
        RedisQueue::getInstance()->sendQueue($queue, $data);

        return ['requestid' => $requestId];
    }

    public function generatedVideo($param)
    {
        $res = Common::setnx('generatedVideo_'.request()->curUserId);
        if($res==false){
            throw new IndexException(4020,'请求频繁');
        }

        $userPlan = UserPromotionPlanModel::getInstance()->find($param['user_planid']);
        if(empty($userPlan)){
            throw new IndexException(4020,'数据不存在');
        }
        if($userPlan['status']>0){
            //throw new IndexException(4020,'已在生成中或已生成完成,不能重复生成');
        }

        $isQueue = false;
        if(isset($param['timbreid']) && $param['timbreid']!==''){
            $isQueue = true;
            $userPlan->timbreid = $param['timbreid'];
        }
        if(isset($param['timbre_volume']) && $param['timbre_volume']!==''){
            $isQueue = true;
            $userPlan->timbre_volume = $param['timbre_volume'];
        }
        if(isset($param['speak_speed']) && $param['speak_speed']!==''){
            $isQueue = true;
            $userPlan->speak_speed = $param['speak_speed'];
        }
        if(isset($param['musicid']) && $param['musicid']!==''){
            $isQueue = true;
            $userPlan->musicid = $param['musicid'];
        }
        if(isset($param['music_volume']) && $param['music_volume']!==''){
            $isQueue = true;
            $userPlan->music_volume = $param['music_volume'];
        }
        if(isset($param['fontid']) && $param['fontid']!==''){
            $userPlan->fontid = $param['fontid'];
        }
        if(isset($param['video_rate']) && $param['video_rate']!==''){
            $userPlan->video_rate = $param['video_rate'];
        }
        $isQueue && $userPlan->status = 0;
        $userPlan->save();

        if($userPlan->status == 0){

            //生成唯一的请求id
            $requestId = Common::getRequestId();

            // 队列名
            $queue = 'asyncGeneratedVideoData';
            // 数据，可以直接传数组，无需序列化
            $data = ['requestid' => $requestId, 'user_planid' => $param['user_planid']];
            // 投递消息
            RedisQueue::getInstance()->sendQueue($queue, $data);
        }

        return ['requestid' => $requestId??''];

    }

}